#ifndef __COLOR_4_HPP__
#define __COLOR_4_HPP__

#include <stdint.h>
#include <assert.h>

#define USE_NLOHMANN_JSON 1
#define USE_FMT_TO_STRING 1


#if USE_NLOHMANN_JSON
#include "nlohmann/json.hpp"
#endif

#if USE_FMT_TO_STRING
#include "spdlog/fmt/fmt.h"
#endif

namespace PocketSurvival::Engine
{
    struct Color4
    {
        union
        {
            struct
            {
                uint8_t A;
                uint8_t R;
                uint8_t G;
                uint8_t B;
            };
            int32_t value;
        };



        constexpr Color4() noexcept;
        constexpr Color4(uint8_t a, uint8_t r, uint8_t g, uint8_t b) noexcept;

        constexpr inline Color4 &operator+=(const Color4 &left);
        constexpr inline Color4 &operator-=(const Color4 &left);
        constexpr inline Color4 &operator*=(uint8_t c);
        constexpr inline Color4 &operator/=(uint8_t c);

        friend constexpr inline bool operator==(const Color4 &left, const Color4 &right)
        {
            return (left.A == right.A) && (left.R == right.R) && (left.G == right.G) && (left.B == right.B);
        }
        friend constexpr inline bool operator!=(const Color4 &left, const Color4 &right)
        {
            return !(left == right);
        }
        friend constexpr inline Color4 operator+(const Color4 &left, const Color4 &right)
        {
            return Color4(left.A + right.A, left.R + right.R, left.G + right.G, left.B + right.B);
        }

        friend constexpr inline Color4 operator-(const Color4 &left, const Color4 &right)
        {
            return Color4(left.A - right.A, left.R - right.R, left.G - right.G, left.B - right.B);
        }
        friend constexpr inline Color4 operator*(const Color4 &left, uint8_t c)
        {
            return Color4(left.A * c, left.R * c, left.G * c, left.B * c);
        }
        friend constexpr inline Color4 operator*(uint8_t c, const Color4 &right)
        {
            return Color4(right.A * c, right.R * c, right.G * c, right.B * c);
        }
        friend constexpr inline Color4 operator+(const Color4 &left)
        {
            return left;
        }
        friend constexpr inline Color4 operator-(const Color4 &left)
        {
            return Color4((uint8_t)-left.A, (uint8_t)-left.R, (uint8_t)-left.G, (uint8_t)-left.B);
        }
        friend constexpr inline Color4 operator/(const Color4 &left, uint8_t divisor)
        {
            assert(divisor < 0 || divisor > 0);
            return Color4(left.A / divisor, left.R / divisor, left.G / divisor, left.B / divisor);
        }

#if USE_NLOHMANN_JSON
        friend inline void to_json(nlohmann::json &json, const Color4 &color);
        friend inline void from_json(const nlohmann::json &json, Color4 &color);
#endif

#if USE_FMT_TO_STRING
        inline std::string toString()
        {
            return fmt::format("{},{},{},{}",R,G,B,A);
        }
        inline std::string toColor3String()
        {
            return fmt::format("{},{},{}",R,G,B);
        }
#endif

    };

    constexpr inline Color4::Color4() noexcept : A(0), R(0), G(0), B(0) {}

    constexpr inline Color4::Color4(uint8_t a, uint8_t r, uint8_t g, uint8_t b) noexcept : A(a), R(r), G(g), B(b) {}

    constexpr inline Color4 &Color4::operator+=(const Color4 &right)
    {
        A += right.A;
        R += right.R;
        G += right.G;
        B += right.B;
        return *this;
    }

    constexpr inline Color4 &Color4::operator-=(const Color4 &right)
    {
        A -= right.A;
        R -= right.R;
        G -= right.G;
        B -= right.B;
        return *this;
    }

    constexpr inline Color4 &Color4::operator*=(uint8_t c)
    {
        A *= c;
        R *= c;
        G *= c;
        B *= c;
        return *this;
    }

    constexpr inline Color4 &Color4::operator/=(uint8_t divisor)
    {
        assert(divisor > 0 || divisor < 0);
        A /= divisor;
        R /= divisor;
        G /= divisor;
        B /= divisor;
        return *this;
    }

#if USE_NLOHMANN_JSON

    inline void to_json(nlohmann::json &json, const Color4 &color)
    {
        json = color.value;
    }
    inline void from_json(const nlohmann::json &json, Color4 &color)
    {
        color.value = json.get<int32_t>();
    }

#endif

}


#undef USE_FMT_TO_STRING
#undef USE_NLOHMANN_JSON

#endif